package cat.joronya.supermanager.service;

import java.io.ByteArrayOutputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthenticationException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.htmlcleaner.ContentNode;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.SimpleHtmlSerializer;
import org.htmlcleaner.TagNode;

import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.util.Log;
import cat.joronya.supermanager.Supermanager;

/**
 * AsyncTask on fem el login i parsejem les dades de la pagina
 * principal.
 * 
 * @author pol
 */
public class LoginSync extends Object//AsyncTask<String,Void,Integer>
{
	private static final String TAG = "supermanager";
	
	// el service
	private SupermanagerService service;
	
	// el client http on fer les peticions
	private DefaultHttpClient client = null;
	
	// login POST
	private static final String LOGIN_POST = InitSync.BASE_URL+"/index.php";
	
	// XPATHs per treure dades de les pagines
	// login error XPATH
	private static final String LOGIN_ERROR_XPATH = "//img[@src='gif/registrar.gif']";
	// jornada XPATH
	private static final String LOGIN_JORNADA_XPATH = "//td[@class='blanca15']";
	// canvis tancats XPATH
	private static final String LOGIN_CANVIS_TANCATS_XPATH = "//small[b='Cambios cerrados']";
	// next jornada XPATH
	private static final String LOGIN_NEXT_JORNADA_XPATH = "//span[@style='color:#FF6300;padding-left:10px;']";
	// duetime XPATH
	private static final String LOGIN_DUETIME_XPATH = "//span[@style='color:#68B8F5;padding-left:10px;']";
	
	// dades extretes de les pagines
	public String jornada = null;
	public String nextJornada = null;
	public String duetime = null;
	public String homeInfo = null;
	public int status = -1;
	
	/**
	 * Constructor amb el intentService que el crida.
	 * @param intentService
	 */
	public LoginSync(SupermanagerService service, DefaultHttpClient client)
	{
		this.service = service;
		this.client = client;
	}
	
	@SuppressWarnings("rawtypes")
	protected void execute(String username, String password)//doInBackground(String... params) 
	{
		try
		{
			// checkejem per connectivitat
			ConnectivityManager cm = (ConnectivityManager) service.getSystemService(Context.CONNECTIVITY_SERVICE);
			boolean online = cm.getActiveNetworkInfo().isConnectedOrConnecting();
			
			if( !online )
				throw new ConnectivityException();
			
			// POST: login
			HttpPost loginHttpPost = new HttpPost(LOGIN_POST);
			HtmlCleaner cleaner = new HtmlCleaner();
			
	        List <NameValuePair> nvps = new ArrayList <NameValuePair>();
	        nvps.add(new BasicNameValuePair("usuario", username));
	        nvps.add(new BasicNameValuePair("clave", password));
	        nvps.add(new BasicNameValuePair("control", "1"));

	        loginHttpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.ISO_8859_1));
	        HttpResponse response = client.execute(loginHttpPost);

	        ByteArrayOutputStream os = new ByteArrayOutputStream();
	        response.getEntity().writeTo(os);
	        String loginPage = os.toString(HTTP.ISO_8859_1);
	        TagNode node = cleaner.clean(loginPage);
	        
	        // login error?
	        Object[] tdError = node.evaluateXPath(LOGIN_ERROR_XPATH);
	        if( tdError.length > 0 )
	        {
	        	TagNode tagError = (TagNode)tdError[0];
	        	if( "img".equals(tagError.getName()) )
	        		throw new AuthenticationException();
	        }
	        
	        // cerquem la jornada i el home info
	        Object[] tdJornada = node.evaluateXPath(LOGIN_JORNADA_XPATH);
	        if( tdJornada.length > 0)
	        {
	        	// cerquem jornada
	        	TagNode tagJornada = (TagNode)tdJornada[0];
	        	for(Object obj: tagJornada.getChildren())
	        	{
	        		if(obj instanceof ContentNode)
	        		{
	        			jornada = obj.toString();
	        			jornada = jornada.replaceFirst("Jornada ", "");
	        			Log.d(TAG,"LoginSync parsing jornada: "+jornada);
	        		}
	        	}
	        	// des d'aqui la home info tambe
	        	List tableBodyHomeInfoChildren = tagJornada.getParent().getParent().getChildren();
	        	// TODO: falta un for pels tr, fins trobar el table a dins d'un d'ells.
	        	TagNode tableBodyHomeInfoTr = (TagNode)tableBodyHomeInfoChildren.get(1);
	        	int tableIndex = 0;
	        	for(Object obj: tableBodyHomeInfoTr.getChildren())
	        	{
	        		TagNode tdHomeInfo = (TagNode)obj;
	        		if( !"td".equals(tdHomeInfo.getName()) )
	        			continue;
	        		
	        		// List tdHomeInfoChildren = tdHomeInfo.getChildren();
	        		for(Object tableHomeInfo: tdHomeInfo.getChildren())
	        		{
	        			// saltem textes
	        			if( tableHomeInfo instanceof ContentNode )
	        				continue;
	        			
	        			//TagNode tableHomeInfo = (TagNode)tdHomeInfoChildren.get(0);
	        			TagNode tableHomeInfoTagNode = (TagNode)tableHomeInfo;
	        			if( !"table".equals(tableHomeInfoTagNode.getName()) )
	        				continue;
	        			
	        			// home info
	        			if( tableIndex == 0 )
	        			{
	        				// serialitzem el tagnode i fills.
	        				SimpleHtmlSerializer htmlSerializer = new SimpleHtmlSerializer(cleaner.getProperties());
	        				StringWriter stringWriter = new StringWriter();
	        				htmlSerializer.write(tableHomeInfoTagNode, stringWriter, "utf-8");
	        				homeInfo = stringWriter.toString();
	        			}
	        			
	        			// close changes
	        			if( tableIndex == 1 )
	        			{
	        				List ccTableBodies = tableHomeInfoTagNode.getChildren();
	        				TagNode ccTableBody = (TagNode)ccTableBodies.get(0);
	        				List ccTrs = ccTableBody.getChildren();
	        				TagNode ccTr = (TagNode)ccTrs.get(0);
	        				List ccTds = ccTr.getChildren();
	        				TagNode ccTd = (TagNode)ccTds.get(1);
	        				
	        				int spanIndex = 0;
	        				for(Object spanObject: ccTd.getChildren())
	        				{
	        					if( !(spanObject instanceof TagNode) )
	        						continue;
	        					
	        					TagNode spanNode = (TagNode)spanObject;

	        					if( !"span".equals(spanNode.getName()) )
	        						continue;
		        					
	        					
	        					if( spanIndex == 0 )	
	        					{
	        						Object spanJornadaObject = spanNode.getChildren().get(0);
	        						if( spanJornadaObject instanceof ContentNode )
	        						{
	        							nextJornada = ((ContentNode)spanJornadaObject).toString();
	        							nextJornada.replace("ª JORNADA", "");
	        						}
	        						else
	        						{
	        							throw new Exception();
	        						}
	        					}
	        					
	        					if( spanIndex == 1 )
	        					{
	        						// tag del dia/hora de tancament
	        						Object spanDuetimeObject = spanNode.getChildren().get(0);
	        						if( spanDuetimeObject instanceof ContentNode )
	        						{
	        							// TODO: tractar la data de fi de canvis
	        							duetime = ((ContentNode)spanDuetimeObject).toString();
	        						}
	        						else
	        						{
	        							throw new Exception();
	        						}
	        					}
	        					spanIndex++;
	        				}
	        			}
		        		
		        		tableIndex++;
	        		}
	        	}
	        }
	        
	        
	        // mirem si estan els canvis tancats
	        Object[] bCanvisTancats = node.evaluateXPath(LOGIN_CANVIS_TANCATS_XPATH);
	        if( bCanvisTancats.length != 0 )
	        	throw new ClosedChangesException();
	        
	        // cerquem la next jornada
	        /*Object[] tdNextJornada = node.evaluateXPath(LOGIN_NEXT_JORNADA_XPATH);
	        // si estan els canvis tancats pot ser que no tinguem next encara
	        if( tdNextJornada.length != 0 )
	        {
	        	TagNode tagNextJornada = (TagNode)tdNextJornada[0];
	        	for(Object obj: tagNextJornada.getChildren())
	        	{
	        		if(obj instanceof ContentNode)
	        		{
	        			nextJornada = obj.toString();
	        		}
	        	}
	        }*/
	        
	        // cerquem el duetime
	        /*Object[] tdDuetime = node.evaluateXPath(LOGIN_DUETIME_XPATH);
	        // si estan els canvis tancats pot ser que no tinguem duetime encara
	        if( tdDuetime.length != 0)
	        {
	        	TagNode tagDuetime = (TagNode)tdDuetime[0];
	        	for(Object obj: tagDuetime.getChildren())
	        	{
	        		if(obj instanceof ContentNode)
	        		{
	        			duetime = obj.toString();
	        		}
	        	}
	        }*/
	        if( duetime == null)
	        	throw new ClosedChangesException();
		}
		catch(ConnectivityException ce){
			status = Supermanager.CONNECTIVITY_ERROR_STATUS;
			return;
		}
		catch(AuthenticationException ae){
			// error d'autenticacio
			status = Supermanager.AUTH_ERROR_STATUS;
			return;
		}
		catch(ClosedChangesException cce){
			status = Supermanager.OPEN_NO_CHANGES_STATUS;
			return;
		}
		catch(Exception e){
			// altre error, notifiquem i anem offline
			status = Supermanager.OTHER_ERROR_STATUS;
			return;
		}

		// si ens hem connectat marquem que estem online
		status = Supermanager.OPEN_STATUS;
    }

	/**
	 * Guardar les dades trobades a DB.
	 */
    protected void onPostExecute(Uri uri) 
    {
    	insertOrUpdateHomeInfo(uri);
    }
    
    private String insertOrUpdateHomeInfo(Uri uri)
	{
    	// insertem home info
		ContentValues values = new ContentValues();
		values.put(Supermanager.Home.DAY, this.jornada);
		values.put(Supermanager.Home.STATUS, this.status);
		values.put(Supermanager.Home.INFO, this.homeInfo);
		values.put(Supermanager.Home.DUE_TIME, this.duetime);
		
		Uri homeUri = Supermanager.Home.CONTENT_URI;
		String lastPathSegment = "0";
		
		// si update no retorna 1 reg, llavors insert
		if( service.getContentResolver().update(uri, 
				values, 
				Supermanager.Home.DAY+" = ? ", 
				new String[]{this.jornada}) == 0 )
		{
			homeUri = service.getContentResolver().insert(uri, values);
			lastPathSegment = homeUri.getLastPathSegment();
			Log.d(TAG, "Inserting home info for day [" + this.jornada
					+ "] with Uri [" + homeUri + "] lastPathSegment ["
					+ lastPathSegment + "]");
		}
		else
		{
			Cursor cursor = service.getContentResolver().
				query(Supermanager.Home.CONTENT_URI, 
					  Supermanager.Home.PROJECTION, 
					  Supermanager.Home.DAY+" = ? ", 
					  new String[]{this.jornada}, 
					  Supermanager.Home.DEFAULT_SORT_ORDER);
			
			if( cursor.moveToFirst() )
			{
				lastPathSegment = ""+cursor.getLong(0);
				homeUri = ContentUris.withAppendedId(Supermanager.Home.CONTENT_URI, cursor.getLong(0));
			}
			Log.d(TAG, "Updating home info for day [" +  this.jornada
					+ "] with Uri [" + homeUri + "] lastPathSegment ["
					+ lastPathSegment + "]");
		}
		
		return lastPathSegment;
	}
}	
